const {app, BrowserWindow, dialog, nativeImage, globalShortcut, ipcMain, protocol, Menu} = require("electron")
const isDev = require("electron-is-dev")
const path = require("path")
const url = require("url")
const {registerIPC, registerNewIPC} = require("./ipc")
const process = require("process")
const {
    initExtraLocalCache,
    getExtraLocalCacheValue,
    initLocalCache,
    setCloeseExtraLocalCache,
    setLocalCache
} = require("./localCache")
const {asyncKillDynamicControl} = require("./handlers/dynamicControlFun")
const {windowStatePatch} = require("./filePath")
const Screenshots = require("./screenshots")
const windowStateKeeper = require("electron-window-state")
const {MenuTemplate} = require("./menu")
const {renderLogOutputFile, getAllLogHandles, closeAllLogHandles, initAllLogFolders} = require("./logFile")

/** 获取缓存数据-软件是否需要展示关闭二次确认弹框 */
const UICloseFlag = "windows-close-flag"

/** 窗口对象 */
let win = null
let engineLinkWin = null

/** 是否展示关闭二次确认弹窗的标志位 */
let closeFlag = true

process.on("uncaughtException", (error) => {
    console.info(error)
})

// 性能优化：https://juejin.cn/post/6844904029231775758

// ======= 全局标志（每个窗口保证只注册一次） =======
let ipcRegistered = false

/**
 * ---------------- 创建 yakitEngineLink 窗口 ----------------
 */
function createEngineLinkWindow() {
    const state = windowStateKeeper({
        defaultWidth: 900,
        defaultHeight: 650,
        path: windowStatePatch,
        file: "yakit-window-state.json"
    })
    const hasPos = Number.isFinite(state.x) && Number.isFinite(state.y)

    engineLinkWin = new BrowserWindow({
        x: hasPos ? state.x : undefined,
        y: hasPos ? state.y : undefined,
        width: 900,
        height: 600,
        minWidth: 900,
        minHeight: 600,
        frame: false,
        autoHideMenuBar: true,
        resizable: false,
        webPreferences: {
            preload: path.join(__dirname, "engineLinkPreload.js"),
            nodeIntegration: true,
            contextIsolation: false,
            sandbox: true
        },
        titleBarStyle: "hidden",
        show: true,
        skipTaskbar: false,
        opacity: 1
    })

    if (!hasPos) engineLinkWin.center()
    if (isDev) engineLinkWin.loadURL("http://127.0.0.1:5173")
    else engineLinkWin.loadFile(path.join(__dirname, "../renderer/engine-link-startup/dist/index.html"))

    engineLinkWin.webContents.setWindowOpenHandler(() => ({action: "deny"}))

    if (isDev) engineLinkWin.webContents.openDevTools({mode: "detach"})

    engineLinkWin.setMenu(null)
    engineLinkWin.setMenuBarVisibility(false)
    if (process.platform === "darwin") engineLinkWin.setWindowButtonVisibility(false)

    engineLinkWin.webContents.on("render-process-gone", (event, details) => {
        renderLogOutputFile(`----- engineLinkWin Render gone ------`)
        renderLogOutputFile(`reason: ${details.reason}, exitCode: ${details.exitCode}`)
        if (details.reason === "crashed") setLocalCache("render-crash-screen", true)
        require("./handlers/logger").saveLogs()
    })

    engineLinkWin.webContents.on("will-navigate", (e) => e.preventDefault())

    engineLinkWin.on("close", (e) => {
        e.preventDefault()
        engineLinkWin.webContents.send("close-engineLinkWin-renderer")
    })

    engineLinkWin.on("closed", () => {
        engineLinkWin = null
    })
}

/**
 * ---------------- 创建主窗口 ----------------
 */
function createWindow() {
    const state = windowStateKeeper({
        defaultWidth: 900,
        defaultHeight: 650,
        path: windowStatePatch,
        file: "yakit-window-state.json"
    })

    win = new BrowserWindow({
        x: state.x,
        y: state.y,
        width: state.width,
        height: state.height,
        minWidth: 900,
        minHeight: 650,
        frame: false,
        autoHideMenuBar: true,
        webPreferences: {
            preload: path.join(__dirname, "preload.js"),
            nodeIntegration: true,
            contextIsolation: false,
            sandbox: true
        },
        titleBarStyle: "hidden",
        show: false,
        skipTaskbar: true,
        opacity: 0
    })

    state.manage(win)
    win.setSize(state.width, state.height)

    if (isDev) win.loadURL("http://127.0.0.1:3000")
    else win.loadFile(path.resolve(__dirname, "../renderer/pages/main/index.html"))

    if (isDev) win.webContents.openDevTools({mode: "detach"})

    win.setMenu(null)
    win.setMenuBarVisibility(false)
    if (process.platform === "darwin") win.setWindowButtonVisibility(false)

    win.webContents.setWindowOpenHandler(() => ({action: "deny"}))
    win.webContents.on("will-navigate", (e) => e.preventDefault())

    win.webContents.on("render-process-gone", (event, details) => {
        renderLogOutputFile(`----- Render gone ------`)
        renderLogOutputFile(`reason: ${details.reason}, exitCode: ${details.exitCode}`)
        if (details.reason === "crashed") setLocalCache("render-crash-screen", true)
        require("./handlers/logger").saveLogs()
    })

    win.on("close", (e) => {
        e.preventDefault()
        state.saveState(win)
        win.webContents.send("close-windows-renderer")
    })

    win.on("minimize", () => {
        win.webContents.send("refresh-token")
        win.webContents.send("minimize-windows-renderer")
    })

    win.on("maximize", () => {
        win.webContents.send("refresh-token")
    })

    win.on("closed", () => {
        win = null
    })
}

/**
 * ---------------- 通用方法 ----------------
 */
// 窗口加载完再发送数据
function safeSend(targetWin, channel, data) {
    if (!targetWin || targetWin.isDestroyed()) return

    const sendFn = () => {
        try {
            targetWin.webContents.send(channel, data)
        } catch (e) {
            console.warn(`[safeSend] send failed: ${channel}`, e)
        }
    }

    if (targetWin.webContents.isLoading()) {
        targetWin.webContents.once("did-finish-load", sendFn)
    } else {
        sendFn()
    }
}

// 主窗口隐藏
function mainWinHide() {
    if (win && !win.isDestroyed()) {
        win.setOpacity(0)
        win.hide()
        win.setSkipTaskbar(true)
    }
}

// 主窗口显示
function mainWinShow() {
    if (engineLinkWin && !engineLinkWin.isDestroyed()) {
        const engineLinkWinBounds = engineLinkWin.getBounds()
        const x = engineLinkWinBounds.x
        const y = engineLinkWinBounds.y
        win.setBounds({x, y})
    }

    if (win && !win.isDestroyed()) {
        win.setOpacity(1)
        win.show()
        win.focus()
        win.setSkipTaskbar(false)
    }
}

// 引擎连接窗口隐藏
function engineLinkWinHide() {
    if (engineLinkWin && !engineLinkWin.isDestroyed()) {
        engineLinkWin.hide()
        engineLinkWin.setOpacity(0)
        engineLinkWin.setSkipTaskbar(true)
    }
}

// 引擎连接窗口显示
function engineLinkWinShow() {
    if (win && !win.isDestroyed()) {
        const winBounds = win.getBounds()
        const linkBounds = engineLinkWin.getBounds()
        const x = winBounds.x + Math.round((winBounds.width - linkBounds.width) / 2)
        const y = winBounds.y + Math.round((winBounds.height - linkBounds.height) / 2)
        engineLinkWin.setBounds({x, y, width: linkBounds.width, height: linkBounds.height})
    }

    if (engineLinkWin && !engineLinkWin.isDestroyed()) {
        engineLinkWin.setOpacity(1)
        engineLinkWin.show()
        engineLinkWin.focus()
        engineLinkWin.setSkipTaskbar(false)
    }
}

/**
 * ---------------- 注册 IPC，只执行一次 ----------------
 */
function registerGlobalIPC() {
    if (ipcRegistered) return
    ipcRegistered = true

    // ------------------- 刷新相关 -------------------
    /** 刷新缓存 */
    ipcMain.handle("trigger-reload", () => {
        win.webContents.reload()
        mainWinHide()
        engineLinkWin.webContents.reload()
        setTimeout(() => {
            engineLinkWinShow()
        }, 500)
        return
    })
    /** 强制清空刷新缓存 */
    ipcMain.handle("trigger-reload-cache", () => {
        win.webContents.reloadIgnoringCache()
        mainWinHide()
        engineLinkWin.webContents.reloadIgnoringCache()
        setTimeout(() => {
            engineLinkWinShow()
        }, 500)
        return
    })

    // ------------------- 主题相关 -------------------
    ipcMain.handle("set-theme", (_e, theme) => {
        ;[
            // 通知所有窗口更新
            engineLinkWin
        ].forEach((w) => safeSend(w, "theme-updated", theme))
    })

    // ------------------- 窗口发送数据操作 -------------------
    // engineLink 完成操作
    ipcMain.handle("engineLinkWin-done", async (event, data) => {
        engineLinkWinHide()
        mainWinShow()
        safeSend(win, "from-engineLinkWin", data)
    })

    // win 完成操作
    ipcMain.handle("yakitMainWin-done", async (event, data) => {
        mainWinHide()
        engineLinkWinShow()
        safeSend(engineLinkWin, "from-win", data)
    })

    // win 远程连接通知 engineLink 更新 认证信息
    ipcMain.handle("updateCredential", async (event, data) => {
        safeSend(engineLinkWin, "from-win-updateCredential", data)
    })

    // ------------------- 软件重启逻辑 -------------------
    ipcMain.handle("relaunch", () => {
        // 优雅销毁窗口
        if (engineLinkWin && !engineLinkWin.isDestroyed()) {
            engineLinkWin.removeAllListeners("close")
            engineLinkWin.destroy()
            engineLinkWin = null
        }

        if (win && !win.isDestroyed()) {
            win.removeAllListeners("close")
            win.destroy()
            win = null
        }

        // 重启应用
        app.relaunch()
        app.exit(0)
    })

    // ------------------- 软件退出逻辑 -------------------
    ipcMain.handle("app-exit", async (e, params) => {
        const {isEngineLinkWin, showCloseMessageBox, isIRify} = params
        const parentWindow = isEngineLinkWin ? engineLinkWin : win

        const exitCleanupOperation = () => {
            if (engineLinkWin) {
                engineLinkWin.close()
                engineLinkWin = null
            }
            if (win) {
                win.close()
                win = null
            }
            closeAllLogHandles()
            app.exit()
        }
        if (closeFlag && showCloseMessageBox && parentWindow) {
            dialog
                .showMessageBox(parentWindow, {
                    icon: nativeImage.createFromPath(
                        path.join(
                            __dirname,
                            isIRify ? "../renderer/src/main/src/assets/yakitSS.png" : "../assets/yakitlogo.pic.jpg"
                        )
                    ),
                    type: "none",
                    title: "提示",
                    defaultId: 0,
                    cancelId: 3,
                    message: "确定要关闭吗？",
                    buttons: ["最小化", "直接退出"],
                    checkboxLabel: "不再展示关闭二次确认？",
                    checkboxChecked: false,
                    noLink: true
                })
                .then(async (res) => {
                    await setCloeseExtraLocalCache(UICloseFlag, !res.checkboxChecked)
                    await asyncKillDynamicControl()
                    if (res.response === 0) {
                        e.preventDefault()
                        engineLinkWin?.minimize()
                        win?.minimize()
                    } else if (res.response === 1) {
                        exitCleanupOperation()
                    } else {
                        e.preventDefault()
                    }
                })
        } else {
            await asyncKillDynamicControl()
            exitCleanupOperation()
        }
    })

    // ------------------- 窗口通信注册 -------------------
    try {
        registerIPC(win)
        console.log("[Main] registerIPC completed")
    } catch (err) {
        console.error("[Main] registerIPC error:", err)
    }
    try {
        registerNewIPC(engineLinkWin, "EngineLink:")
        console.log("[engineLinkWin] registerNewIPC completed")
    } catch (err) {
        console.error("[engineLinkWin] registerNewIPC error:", err)
    }
}

/**
 * set software menu
 */
const menu = Menu.buildFromTemplate(MenuTemplate)
Menu.setApplicationMenu(menu)

/**
 * ---------------- App Ready ----------------
 */
app.whenReady().then(() => {
    /**
     * init-log-folders:
     * 存在则检查文件数量是否超过10个，超过则只保留最近10个文件
     * 不存在则新建文件夹
     */
    initAllLogFolders()

    /** 获取缓存数据并储存于软件内 */
    initLocalCache()
    /** 获取扩展缓存数据并储存于软件内(是否弹出关闭二次确认弹窗) */
    initExtraLocalCache(() => {
        const cacheFlag = getExtraLocalCacheValue(UICloseFlag)
        closeFlag = cacheFlag === undefined ? true : cacheFlag
    })

    // 截图功能注册
    if (["darwin", "win32"].includes(process.platform)) {
        const screenshots = new Screenshots({singleWindow: true})
        ipcMain.handle("activate-screenshot", () => {
            screenshots.startCapture()
            globalShortcut.register("esc", () => {
                screenshots.endCapture()
                globalShortcut.unregister("esc")
            })
        })
        globalShortcut.register("Control+Shift+q", () => {
            screenshots.endCapture()
            globalShortcut.unregister("esc")
        })
        screenshots.on("ok", () => {
            if (screenshots.$win?.isFocused()) {
                screenshots.endCapture()
                globalShortcut.unregister("esc")
            }
        })
        screenshots.on("cancel", () => {
            globalShortcut.unregister("esc")
        })
    }

    // 注册协议
    protocol.registerFileProtocol("atom", (request, callback) => {
        const filePath = url.fileURLToPath("file://" + request.url.slice("atom://".length))
        callback(filePath)
    })

    try {
        getAllLogHandles()
    } catch (error) {}

    createWindow()
    mainWinHide()
    createEngineLinkWindow()

    app.on("activate", function () {
        if (BrowserWindow.getAllWindows().length === 0) {
            createEngineLinkWindow()
        }
    })

    // IPC
    try {
        registerGlobalIPC()
    } catch (error) {}
})

/**
 * ---------------- 全局退出逻辑 ----------------
 */
// 这个退出压根执行不到 win.on("close") 阻止了默认行为
app.on("window-all-closed", () => {
    app.quit()
})
